/// @tags: SegTreeSplit ODT
#include <cctype>
#include <cstdio>
#include <cstring>
#include <set>

namespace BlueQuantum {

typedef std::set<int>::iterator iter;

int const N = 1e5 + 5, M = 25;

template <typename T>
inline T &read(T &x) {
  x = 0;
  bool f = false;
  short ch = getchar();
  while (!isdigit(ch)) {
    if (ch == '-') f = true;
    ch = getchar();
  }
  while (isdigit(ch)) x = x * 10 + (ch ^ '0'), ch = getchar();
  if (f) x = -x;
  return x;
}

struct Node {
  int ls, rs, tot;
} tr[(N + 50000) * 30];

int n, q, tot;
int root[N];
bool typ[N];
char str[N];
std::set<int> set;

void insert(int pos, int &x, int l = 0, int r = M) {
  tr[x = ++tot].tot = 1;
  if (l == r) return;
  int mid = (l + r) >> 1;
  if (pos <= mid) insert(pos, tr[x].ls, l, mid);
  else
    insert(pos, tr[x].rs, mid + 1, r);
}

void split(int &x, int y, int k, bool typ) {
  if (!y || k == tr[y].tot) return;
  tr[x = ++tot].tot = tr[y].tot - k;
  tr[y].tot = k;
  if (typ) {
    if (k <= tr[tr[y].ls].tot)
      split(tr[x].ls, tr[y].ls, k, typ), tr[x].rs = tr[y].rs, tr[y].rs = 0;
    else
      split(tr[x].rs, tr[y].rs, k - tr[tr[y].ls].tot, typ);
  } else {
    if (k <= tr[tr[y].rs].tot)
      split(tr[x].rs, tr[y].rs, k, typ), tr[x].ls = tr[y].ls, tr[y].ls = 0;
    else
      split(tr[x].ls, tr[y].ls, k - tr[tr[y].rs].tot, typ);
  }
}

void merge(int &x, int y) {
  if (!(x && y)) return x |= y, void();
  tr[x].tot += tr[y].tot;
  merge(tr[x].ls, tr[y].ls);
  merge(tr[x].rs, tr[y].rs);
}

inline iter split(int pos) {
  iter it = set.lower_bound(pos);
  if (*it == pos) return it;
  --it;
  split(root[pos], root[*it], pos - *it, typ[pos] = typ[*it]);
  return set.insert(pos).first;
}

void print(int x, bool typ, int l = 0, int r = M) {
  if (!x) return;
  if (l == r) {
    while (tr[x].tot-- > 0) putchar('a' + l);
    return;
  }
  int mid = (l + r) >> 1;
  typ ? (print(tr[x].ls, typ, l, mid), print(tr[x].rs, typ, mid + 1, r))
      : (print(tr[x].rs, typ, mid + 1, r), print(tr[x].ls, typ, l, mid));
}

inline int main() {
  read(n), read(q);
  scanf("%s", str + 1);
  for (int i = 1; i <= n; ++i) {
    insert(str[i] - 'a', root[i]);
    set.insert(i);
  }
  set.insert(n + 1);
  for (int l, r, k; q; --q) {
    read(l), read(r), read(k);
    iter lit = split(l), rit = split(r + 1);
    for (iter i = ++lit; i != rit; ++i) merge(root[l], root[*i]);
    typ[l] = k;
    set.erase(lit, rit);
  }
  for (iter i = set.begin(), end = set.end(); i != end; ++i) print(root[*i], typ[*i]);
  return 0;
}

}  // namespace BlueQuantum

int main() {
#ifndef ONLINE_JUDGE
#ifdef LOCAL
  freopen("/tmp/CodeTmp/testdata.in", "r", stdin);
  freopen("/tmp/CodeTmp/testdata.out", "w", stdout);
#else
  freopen("CF558E A Simple Task.in", "r", stdin);
  freopen("CF558E A Simple Task.out", "w", stdout);
#endif
#endif

  return BlueQuantum::main();
}